#!/usr/bin/env python 2.6
#=============================================================================
'''
    Execute tests by calling the surveyor cmdLine module directly
    There are also cmdLine system tests that run Surveyor from a batch
    file, but this is more convienent for more detailed testing.
'''
#=============================================================================
# Copyright 2011, Matt Peloquin. This file is part of Code Surveyor,
# covered under GNU GPL v3 and is distributed WITHOUT ANY WARRANTY
#=============================================================================
import os
import sys
import unittest

import test_syspathfix
from framework import cmdlineapp

ExtraArgStr = None
PathToMeasure = None

TestFilePath = "TestFiles"
MeasureFilePath = os.path.join(TestFilePath, 'MeasureFiles')

def suite(testNamePrefix='test_', extraArgStr=None, pathToMeasure=None):
    global ExtraArgStr, PathToMeasure
    ExtraArgStr = extraArgStr
    PathToMeasure = pathToMeasure
    return unittest.makeSuite(SystemTests, testNamePrefix)


class SystemTests(unittest.TestCase):

    myPath = os.path.dirname(__file__)
    testPath = ""

    # Setup the folder for where surveyor lives, which is the
    # first argument in our mocked up sys.args command-line
    firstArg = os.path.abspath(os.path.join(myPath, '..', '..', 'surveyor', 'DUMMY_SURVEYOR_NAME'))

    # Path and file prefix for the output files
    outPath = os.path.abspath(os.path.join(myPath, '..', 'output'))
    outFilePath = os.path.join(outPath, "System_")

    @classmethod
    def setUpClass(cls):
        print "================================================="
        print "           Starting System Tests                 "
        print "================================================="

    def setUp(self):
        # The target path to measure for all tests
        if PathToMeasure is None:
            # Make sure we find test files from where we are running
            self.testPath = os.path.abspath(os.path.join(self.myPath, '..', TestFilePath))
        else:
            self.testPath = PathToMeasure
        print "\nMeasuring: {0}".format(self.testPath)

        # Setup the path for the output file based on this testcase name
        head, tail = os.path.splitext(self.id())
        self.outFile = open(self.outFilePath + tail[1:] + ".txt", 'w')
        self.testOutName = self.outFilePath + tail[1:] + ".csv"

        # Start of almost every test command
        # Run surveyor with mocked-up command line, with output going to our output file
        self.cmdLineStart = [self.firstArg, "-o", self.testOutName]

    def runSurveyorList(self, cmdLine):
        if ExtraArgStr is not None:
            cmdLine.extend(ExtraArgStr.split(" "))
        print "\n   Running: {0}".format(' '.join(cmdLine))
        return cmdlineapp.run_job(self.cmdLineStart + cmdLine, self.outFile)

    def runSurveyor(self, cmdLineArgs):
        return self.runSurveyorList(cmdLineArgs.split(" "))

    def assertSurveyor(self, cmdLineArgs):
        self.assertTrue(self.runSurveyor(cmdLineArgs.strip() + " - " + self.testPath))

    #--------------------------------------------------------------------------

    def test_Aggregate(self):
        # Aggregate only works with analysis output
        self.assertFalse(self.runSurveyor("-g"))
        self.assertSurveyor("-g SHOULD_FAIL_SILENTLY all" )
        # Need to build lists here since we have to pass strings in on command line
        defList = ["-cc", "analyze DupeLines * *.cs", "-", os.path.join(self.testPath, 'MeasureFiles')]
        self.assertFalse(self.runSurveyorList(defList + ["-g", "SHOULD_FAIL", "all"]))

#        self.assertTrue(self.runSurveyorList(defList + ["-g", "DupeLine.CRC", "all"]))
#        self.assertTrue(self.runSurveyorList(defList + ["-g", "DupeLine.CRC",
#                "['DupeLine.Files', 'DupeLine.Count']","DupeLine.Count", "2" ]))


    def test_Combos(self):
        self.assertSurveyor("-ad -w 2 -p 50")
        self.assertSurveyor("-t -v 16 -p -e -sd *svn EX:*.cs")
        self.assertTrue(self.runSurveyor("-v -q -f file.* - " +
                os.path.join(self.testPath, 'MeasureFiles', '*.vb') + " -o " +
                os.path.join(self.outPath, 'System_test_ComboVb.csv')))
        self.assertTrue(self.runSurveyor("-c surveyor.examples -r xml -v -q - " +
                os.path.join(self.testPath, '..', '*.java') + " -o " +
                os.path.join(self.outPath, 'System_test_ComboCs.xml')))

    def test_Config(self):
        self.assertFalse(self.runSurveyor("-c NO_CONFIG_EXISTS"))
        self.assertFalse(self.runSurveyor("-c surveyor.malformed1 - TestFiles"))
        self.assertFalse(self.runSurveyor("-c surveyor.malformed2 - TestFiles"))
        self.assertFalse(self.runSurveyor("-c surveyor.malformed3 - TestFiles"))
        self.assertFalse(self.runSurveyor("-c surveyor.malformed4 - TestFiles"))
        self.assertFalse(self.runSurveyor("-c surveyor.malformed5 - TestFiles"))
        self.assertSurveyor("-c surveyor.examples")
        self.assertTrue(self.runSurveyor("-c surveyor.test " + os.path.join(self.testPath, 'MeasureFiles')))
        self.assertSurveyor("-ci")
        self.assertTrue(self.runSurveyorList(["-cc", 'measure NBNC * *']))

    def test_Debug(self):
        debugOut = os.path.join(self.outPath, 'dbg.test')
        self.assertSurveyor("-z " + debugOut)
        self.assertSurveyor("-z1fscnqm " + debugOut + " - *.py;*.txt")
        self.assertSurveyor("-z2fscnqm " + debugOut + " - *.java")
        self.assertSurveyor("-w 4 -z3fscnqm " + debugOut + " 150 - *.h")
        self.assertSurveyor("-w 1 -z4fscnqm " + debugOut + " - *.c")
        self.assertFalse(self.runSurveyor("-n -w 1 -z4t " + debugOut + " 140 -c NO_CONFIG"))

    def test_Delta(self):
        self.assertFalse(self.runSurveyor("-d dummy"))
        self.assertSurveyor("-d " + self.testPath)
        self.assertSurveyor("-dd " + self.testPath)
        self.assertSurveyor("-d " + os.path.join(self.testPath, '..'))
        self.assertTrue(self.runSurveyor("-d " + os.path.join(self.testPath, 'Diff', 'Diff1') + " - " +
                os.path.join(self.testPath, 'Diff', 'Diff2')))
        self.assertTrue(self.runSurveyor("-d " + os.path.join(self.testPath, 'Diff', 'Diff2') + " - " +
                os.path.join(self.testPath, 'Diff', 'Diff1', '*.cs')))

    def test_Dupe(self):
        self.assertSurveyor("-e")
        self.assertSurveyor("-e 100")
        self.assertTrue(self.runSurveyor("-e - " + os.path.join(self.testPath, 'Diff', '*.cs')))
        self.assertTrue(self.runSurveyor("-e crc - Diff"))

    def test_Fails(self):
        self.assertFalse(self.runSurveyor("-?"))
        self.assertFalse(self.runSurveyor("-? c"))
        self.assertFalse(self.runSurveyor("-w 0"))
        self.assertFalse(self.runSurveyor("-w -1"))
        self.assertFalse(self.runSurveyor("-w 2000"))

    def test_Metadata(self):
        self.assertSurveyor("-m path 1 -m date %Y -m d %m -m d %d")
        self.assertSurveyor("-m zAll")
        self.assertSurveyor("-m r -m size -m absPath -f BAD")
        self.assertSurveyor("-f metadata")

    def test_Output(self):
        self.assertSurveyor("-r csv")
        self.assertSurveyor("-r tab -o " + os.path.join(self.outPath, 'System_test_Output.tab'))
        self.assertSurveyor("-r paragraph -o " + os.path.join(self.outPath, 'System_test_Output.para'))
        self.assertSurveyor("-r xml -o " + os.path.join(self.outPath, 'System_test_Output.xml'))
        self.assertSurveyor("-r xml -o stdout - ControlView.cs")

    def test_Paths(self):
        self.assertTrue(self.runSurveyor(self.testPath))
        self.assertTrue(self.runSurveyor(self.testPath + " " + self.testPath + " " +
                os.path.join(self.testPath, '*.c')))
        self.assertTrue(self.runSurveyor(os.path.join(self.testPath, '*.py')))
        self.assertTrue(self.runSurveyor(os.path.join(self.testPath, '*.*')))
        self.assertTrue(self.runSurveyor(os.path.join(self.testPath, 'BAD_FILE')))
        self.assertFalse(self.runSurveyor(os.path.join("BAD_DIR", '*.c')))

    def test_ScanAndSkip(self):
        self.assertSurveyor("-a")
        self.assertSurveyor("-am")
        self.assertSurveyor("-an")
        self.assertSurveyor("-ad")
        self.assertSurveyor("-sd output")
        self.assertSurveyor("-sl 1")
        self.assertSurveyor("-i *MeasureFiles*")
        self.assertSurveyor("-i " + os.path.join('*', 'MeasureFiles'))
        self.assertSurveyor("-i DOES_NOT_EXIST")
        self.assertSurveyor("-a -sf *.csv -sn")
        self.assertSurveyor("-a -sb")

    #--------------------------------------------------------------------------
    # These tests will be compared to the Oracle folder

    def test_Oracle(self):
        # We need to have a relative path to the test files, so the Oracle output will match
        # up on different machines (TestFilePath is an absolute path to ensure test files are found)
        # Thus the Oracle tests will only produce comparable results when run from codesurveyor\tests
        # We also must use the -m r option to avoid metadata that might change with different
        # oracle runs, like for absolute path
        self.assertTrue(self.runSurveyor("-w 1 -c surveyor.test -sb -m r -m p 8 -m s -m d %Y -m d %m" +
                " - " + MeasureFilePath + " -o " +
                os.path.join(self.outPath, 'Oracle_Test1.csv')))
        self.assertTrue(self.runSurveyor("-w 1 -c surveyor.test -sb -m r -m p 4 -r xml" +
                " - " + MeasureFilePath + " -o " +
                os.path.join(self.outPath, 'Oracle_Test2.xml')))
        self.assertTrue(self.runSurveyor("-w 1 -f nbnc.*;file.* -m r -m p 4" +
                " -d " + os.path.join(TestFilePath, 'Diff', 'Diff1') +
                " - " + os.path.join(TestFilePath, 'Diff', 'Diff2') + " -o " +
                os.path.join(self.outPath, 'Oracle_Test3.csv')))
        self.assertTrue(self.runSurveyor("-w 1 -ad -f nbnc.*;file.* -m r -m p 10 -p -i *MeasureFiles;*Searching*" +
                " - " + MeasureFilePath + " -o " +
                os.path.join(self.outPath, 'Oracle_Test4.csv')))
        self.assertTrue(self.runSurveyor("-w 1 -f nbnc.*;file.* -m r" +
                " - " + os.path.join(MeasureFilePath, '*.py') + " -o " +
                os.path.join(self.outPath, 'Oracle_Test5.csv')))
        self.assertTrue(self.runSurveyor("-w 1 -a -f nbnc.*;file.* -m r -m p 4 -sb" +
                " - " + os.path.join(MeasureFilePath, "EX:*.py:*.cs") + " -o " +
                os.path.join(self.outPath, 'Oracle_Test6.csv')))

    def test_OracleOut(self):
        # In this test we will compare stdout as well as measure output -- may prove brittle
        oracleOutPath = os.path.join(self.outPath, 'Oracle_TestOut.txt')
        self.outFile.write("Look for output in " + oracleOutPath)
        self.outFile.close()
        self.outFile = open(oracleOutPath, 'w')
        self.assertTrue(self.runSurveyor("-w 1 -ad -f nbnc.*;file.* -q -m r -m d 4 - *.java - " + TestFilePath +
                " -z3 " + os.path.join(self.outPath, 'Oracle_TestOut.txt') +
                " -o " + os.path.join(self.outPath, 'Oracle_TestOut.csv')))

    #--------------------------------------------------------------------------

    def tearDown(self):
        print "Output is in: {0}".format(self.outFile.name)
        self.outFile.close()


if __name__ == '__main__':

    testSuite = suite()
    if len(sys.argv) > 1 and len(sys.argv) <= 4:
        testSuite = suite(*tuple(arg for arg in sys.argv[1:]))

    unittest.TextTestRunner(verbosity=4).run(unittest.TestSuite(testSuite))

